package com.xiaobo.framework.config.websocket;



import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaobo.framework.api.AccountData;
import com.xiaobo.framework.api.bean.Account;
import com.xiaobo.framework.api.bean.Message;
import com.xiaobo.framework.api.bean.ShareSession;
import com.xiaobo.framework.repository.MessageDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: <a href="get_xiaobo@163.com">Josh_Xu</a>
 * @description:
 * @create: 2020-04-23 23:42
 **/
@Component
@Slf4j
public class WebSocketHandler extends TextWebSocketHandler {


    //分层处理这个handler 连接和消息分开处理

    @Autowired
    private MessageDao messageDao;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     *     单体应用session存储
     *     分布式架构解决分案
     *      1.消息中间发布订阅的方式，模拟session共享
     *      2.redis序列化session
      */
    public static final Map<Long, WebSocketSession> SESSIONS = new ConcurrentHashMap<>();

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

   String time =  DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());

    @Override
    @SuppressWarnings("all")
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        Long uid = (Long) session.getAttributes().get("uid");

        JsonNode jsonNode = OBJECT_MAPPER.readTree(message.getPayload());
        Long fromId = jsonNode.get("fromId").asLong();
        Long toId = jsonNode.get("toId").asLong();
        String msg = jsonNode.get("msg").asText();
        //获取发送人与接收人信息
        Account fromInfo = AccountData.ACCOUNT_MAP.get(fromId);
        Account toInfo = AccountData.ACCOUNT_MAP.get(toId);

        /*Account fromInfo = Account.builder().id(fromId).username("小胡").build();
        Account toInfo = Account.builder().id(toId).username("小波").build();*/
        Message sendMessage = Message.builder()
                .from(fromInfo)//发送者信息
                .to(toInfo)//接受者信息
                .msg(msg)//消息
                .sendDate(time)
                .status(0)
                .build();
        //将消息保存到mongdb中
        this.messageDao.saveMessage(sendMessage);

        //判断接受用户是否在线
        WebSocketSession toSession = SESSIONS.get(toId);
        String path = String.format("session:im:%s", uid.toString());
        //判断redis是否在线
        ShareSession shareSession = (ShareSession) this.redisTemplate.opsForValue().get(path);
        if (null!=shareSession && shareSession.isStatus()){
            if (null != toSession && toSession.isOpen()) {
                //TODO 消息序列化标准待定
                sendMessage.setStatus(1);
                toSession.sendMessage(new TextMessage(OBJECT_MAPPER.writeValueAsString(sendMessage)));
                //修改mongodb里面的消息状态
                this.messageDao.updateMessageState(sendMessage.getId(),1);
            }
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Long uid = (Long) session.getAttributes().get("uid");
        SESSIONS.put(uid, session);
        session.sendMessage(new TextMessage("服务已连接!"));
        String path = String.format("session:im:%s", uid.toString());
        ShareSession imSession = ShareSession.builder().uid(uid).status(true).build();
        this.redisTemplate.opsForValue().set(path,imSession);
        log.info(uid+"加入连接");
        log.info("连接人数{}",SESSIONS.size());
    }

    /**
     * 断开连接不能再发送消息
     *
     * @param session
     * @param status
     * @throws IOException
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws IOException {
        Long uid = (Long) session.getAttributes().get("uid");
        SESSIONS.remove(uid,session);
        String path = String.format("session:im:%s", uid.toString());
        this.redisTemplate.delete(path);
        log.info(uid+"断开连接");
        log.info("连接人数{}",SESSIONS.size());
    }
}
